package de.fhdw.seminar.xtext.generator;

import com.google.common.base.Objects;
import com.google.common.collect.Iterators;
import de.fhdw.seminar.xtext.generator.UmlDslGenerator;
import de.fhdw.seminar.xtext.umlDsl.BuiltInTypes;
import de.fhdw.seminar.xtext.umlDsl.UmlAssociation;
import de.fhdw.seminar.xtext.umlDsl.UmlAttribute;
import de.fhdw.seminar.xtext.umlDsl.UmlClass;
import de.fhdw.seminar.xtext.umlDsl.UmlModel;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.eclipse.xtext.generator.IFileSystemAccess;
import org.eclipse.xtext.xbase.lib.Functions.Function0;
import org.eclipse.xtext.xbase.lib.IteratorExtensions;

@SuppressWarnings("all")
public class UmlDslGeneratorTS extends UmlDslGenerator {
  private final String Field_HierarchyName = "Hierarchy";
  
  private HashMap<UmlClass,HashSet<UmlClass>> hierarchy = new Function0<HashMap<UmlClass,HashSet<UmlClass>>>() {
    public HashMap<UmlClass,HashSet<UmlClass>> apply() {
      HashMap<UmlClass,HashSet<UmlClass>> _hashMap = new HashMap<UmlClass,HashSet<UmlClass>>();
      return _hashMap;
    }
  }.apply();
  
  private StringBuilder output = new Function0<StringBuilder>() {
    public StringBuilder apply() {
      StringBuilder _stringBuilder = new StringBuilder();
      return _stringBuilder;
    }
  }.apply();
  
  public void doGenerate(final Resource resource, final IFileSystemAccess fsa) {
    UmlModel model = null;
    TreeIterator<EObject> _allContents = resource.getAllContents();
    Iterator<UmlModel> _filter = Iterators.<UmlModel>filter(_allContents, UmlModel.class);
    Iterable<UmlModel> _iterable = IteratorExtensions.<UmlModel>toIterable(_filter);
    for (final UmlModel cM : _iterable) {
      model = cM;
    }
    this.determineHierarchies(model);
    CharSequence _generateObjectTable = this.generateObjectTable();
    this.output.append(_generateObjectTable);
    CharSequence _generateHierarchyTables = this.generateHierarchyTables();
    this.output.append(_generateHierarchyTables);
    StringBuilder _generateManyAttributes = this.generateManyAttributes();
    this.output.append(_generateManyAttributes);
    StringBuilder _generateAssociations = this.generateAssociations();
    this.output.append(_generateAssociations);
    fsa.generateFile("TS.txt", this.output);
  }
  
  public void determineHierarchies(final UmlModel model) {
    EList<UmlClass> _classes = model.getClasses();
    for (final UmlClass umlClass : _classes) {
      {
        UmlClass root = this.fetchRootClass(umlClass);
        boolean _containsKey = this.hierarchy.containsKey(root);
        boolean _not = (!_containsKey);
        if (_not) {
          HashSet<UmlClass> _hashSet = new HashSet<UmlClass>();
          this.hierarchy.put(root, _hashSet);
        }
        HashSet<UmlClass> _get = this.hierarchy.get(root);
        _get.add(umlClass);
      }
    }
  }
  
  public CharSequence generateObjectTable() {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("CREATE TABLE ");
    _builder.append(this.ObjectTableName, "");
    _builder.append("  (");
    _builder.newLineIfNotEmpty();
    _builder.append(this.IdName, "");
    _builder.append(" ");
    _builder.append(this.IdDataType, "");
    _builder.append(" ");
    _builder.append(this.PrimaryKeyConstraint, "");
    _builder.append(" ");
    _builder.append(this.Comma, "");
    _builder.append(" ");
    _builder.newLineIfNotEmpty();
    _builder.append(this.TypeColumnName, "");
    _builder.append(" ");
    _builder.append(this.StringDataType, "");
    _builder.append(" ");
    _builder.append(this.Comma, "");
    _builder.newLineIfNotEmpty();
    _builder.append(this.Field_HierarchyName, "");
    _builder.append(" ");
    _builder.append(this.StringDataType, "");
    _builder.newLineIfNotEmpty();
    _builder.append(")");
    _builder.newLine();
    return _builder;
  }
  
  public CharSequence generateHierarchyTables() {
    StringConcatenation _builder = new StringConcatenation();
    {
      Set<UmlClass> _keySet = this.hierarchy.keySet();
      for(final UmlClass rootClass : _keySet) {
        CharSequence _generateHierarchyTable = this.generateHierarchyTable(rootClass);
        _builder.append(_generateHierarchyTable, "");
        _builder.newLineIfNotEmpty();
      }
    }
    return _builder;
  }
  
  public CharSequence generateHierarchyTable(final UmlClass rootClass) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("CREATE TABLE ");
    String _generateHierarchyTableName = this.generateHierarchyTableName(rootClass);
    _builder.append(_generateHierarchyTableName, "");
    _builder.append(" (");
    _builder.newLineIfNotEmpty();
    _builder.append(this.IdName, "");
    _builder.append(" ");
    _builder.append(this.IdDataType, "");
    _builder.append(" ");
    _builder.append(this.PrimaryKeyConstraint, "");
    _builder.append(",");
    _builder.newLineIfNotEmpty();
    HashSet<UmlClass> hierarchySet = this.hierarchy.get(rootClass);
    _builder.newLineIfNotEmpty();
    {
      Iterator<UmlClass> _iterator = hierarchySet.iterator();
      Iterable<UmlClass> _iterable = IteratorExtensions.<UmlClass>toIterable(_iterator);
      for(final UmlClass currentClass : _iterable) {
        {
          EList<UmlAttribute> _attributes = currentClass.getAttributes();
          for(final UmlAttribute attribute : _attributes) {
            {
              boolean _isIsMany = attribute.isIsMany();
              boolean _not = (!_isIsMany);
              if (_not) {
                CharSequence _generateAttribute = this.generateAttribute(attribute);
                _builder.append(_generateAttribute, "");
                _builder.append(this.Comma, "");
                _builder.append(" ");
                _builder.newLineIfNotEmpty();
              }
            }
          }
        }
      }
    }
    _builder.append("FOREIGN KEY (");
    _builder.append(this.IdName, "");
    _builder.append(") REFERENCES ");
    _builder.append(this.ObjectTableName, "");
    _builder.append("(");
    _builder.append(this.IdName, "");
    _builder.append(")");
    _builder.newLineIfNotEmpty();
    _builder.append(") ");
    _builder.newLine();
    return _builder;
  }
  
  public String generateHierarchyTableName(final UmlClass theClass) {
    String _name = theClass.getName();
    return (this.ClassTablePrefix + _name);
  }
  
  public CharSequence generateAttribute(final UmlAttribute attribute) {
    StringConcatenation _builder = new StringConcatenation();
    String _name = attribute.getName();
    _builder.append(_name, "");
    _builder.append(" ");
    BuiltInTypes _type = attribute.getType();
    String _generateBuiltInTypeName = this.generateBuiltInTypeName(_type);
    _builder.append(_generateBuiltInTypeName, "");
    return _builder;
  }
  
  public String generateBuiltInTypeName(final BuiltInTypes linktype) {
    String _switchResult = null;
    boolean _matched = false;
    if (!_matched) {
      if (Objects.equal(linktype,BuiltInTypes.BOOLEAN)) {
        _matched=true;
        _switchResult = this.BooleanDataType;
      }
    }
    if (!_matched) {
      if (Objects.equal(linktype,BuiltInTypes.STRING)) {
        _matched=true;
        _switchResult = this.StringDataType;
      }
    }
    if (!_matched) {
      if (Objects.equal(linktype,BuiltInTypes.INTEGER)) {
        _matched=true;
        _switchResult = this.IntegerDataType;
      }
    }
    if (!_matched) {
      _switchResult = "";
    }
    return _switchResult;
  }
  
  public StringBuilder generateManyAttributes() {
    StringBuilder _stringBuilder = new StringBuilder();
    StringBuilder result = _stringBuilder;
    Set<UmlClass> _keySet = this.hierarchy.keySet();
    for (final UmlClass rootClass : _keySet) {
      HashSet<UmlClass> _get = this.hierarchy.get(rootClass);
      for (final UmlClass currentClass : _get) {
        EList<UmlAttribute> _attributes = currentClass.getAttributes();
        for (final UmlAttribute attribute : _attributes) {
          boolean _isIsMany = attribute.isIsMany();
          if (_isIsMany) {
            CharSequence _generateManyAttribute = this.generateManyAttribute(rootClass, attribute);
            result.append(_generateManyAttribute);
          }
        }
      }
    }
    return result;
  }
  
  public CharSequence generateManyAttribute(final UmlClass root, final UmlAttribute attribute) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("CREATE TABLE ");
    _builder.append(this.AttTablePrefix, "");
    String _name = root.getName();
    _builder.append(_name, "");
    _builder.append("_");
    String _name_1 = attribute.getName();
    _builder.append(_name_1, "");
    _builder.append(" (");
    _builder.newLineIfNotEmpty();
    _builder.append(this.IdName, "");
    _builder.append(" ");
    _builder.append(this.IdDataType, "");
    _builder.append(" ");
    _builder.append(this.PrimaryKeyConstraint, "");
    _builder.append(",");
    _builder.newLineIfNotEmpty();
    _builder.append("Owner ");
    _builder.append(this.IdDataType, "");
    _builder.append(",");
    _builder.newLineIfNotEmpty();
    _builder.append("Att_Value ");
    BuiltInTypes _type = attribute.getType();
    String _generateBuiltInTypeName = this.generateBuiltInTypeName(_type);
    _builder.append(_generateBuiltInTypeName, "");
    _builder.append(",");
    _builder.newLineIfNotEmpty();
    _builder.append("FOREIGN KEY (Owner) REFERENCES ");
    String _generateHierarchyTableName = this.generateHierarchyTableName(root);
    _builder.append(_generateHierarchyTableName, "");
    _builder.append("(");
    _builder.append(this.IdName, "");
    _builder.append(")");
    _builder.newLineIfNotEmpty();
    _builder.append(")");
    _builder.newLine();
    return _builder;
  }
  
  public StringBuilder generateAssociations() {
    StringBuilder _stringBuilder = new StringBuilder();
    StringBuilder result = _stringBuilder;
    Set<UmlClass> _keySet = this.hierarchy.keySet();
    for (final UmlClass rootClass : _keySet) {
      HashSet<UmlClass> _get = this.hierarchy.get(rootClass);
      for (final UmlClass currentClass : _get) {
        EList<UmlAssociation> _associations = currentClass.getAssociations();
        for (final UmlAssociation association : _associations) {
          CharSequence _generateAssociation = this.generateAssociation(rootClass, association);
          result.append(_generateAssociation);
        }
      }
    }
    return result;
  }
  
  public CharSequence generateAssociation(final UmlClass root, final UmlAssociation association) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("CREATE TABLE ");
    _builder.append(this.AssocTablePrefix, "");
    String _name = root.getName();
    _builder.append(_name, "");
    _builder.append("_");
    String _name_1 = association.getName();
    _builder.append(_name_1, "");
    _builder.append(" (");
    _builder.newLineIfNotEmpty();
    _builder.append(this.IdName, "");
    _builder.append(" ");
    _builder.append(this.IdDataType, "");
    _builder.append(" ");
    _builder.append(this.PrimaryKeyConstraint, "");
    _builder.append(",");
    _builder.newLineIfNotEmpty();
    _builder.append("Owner ");
    _builder.append(this.IdDataType, "");
    _builder.append(",");
    _builder.newLineIfNotEmpty();
    _builder.append("Target ");
    _builder.append(this.IdDataType, "");
    _builder.append(",");
    _builder.newLineIfNotEmpty();
    _builder.append("FOREIGN KEY (Owner) REFERENCES ");
    String _generateHierarchyTableName = this.generateHierarchyTableName(root);
    _builder.append(_generateHierarchyTableName, "");
    _builder.append("(");
    _builder.append(this.IdName, "");
    _builder.append("),");
    _builder.newLineIfNotEmpty();
    _builder.append("FOREIGN KEY (Target) REFERENCES ");
    UmlClass _type = association.getType();
    UmlClass _fetchRootClass = this.fetchRootClass(_type);
    String _generateHierarchyTableName_1 = this.generateHierarchyTableName(_fetchRootClass);
    _builder.append(_generateHierarchyTableName_1, "");
    _builder.append("(");
    _builder.append(this.IdName, "");
    _builder.append(")");
    _builder.newLineIfNotEmpty();
    _builder.append(")");
    _builder.newLine();
    return _builder;
  }
  
  /**
   * Returns <tt>currentClass</tt>, if it has no supertype,
   * or the first parent of <tt>currentClass</tt>, which has no supertype
   */
  public UmlClass fetchRootClass(final UmlClass currentClass) {
    UmlClass _superType = currentClass.getSuperType();
    boolean _equals = Objects.equal(_superType, null);
    if (_equals) {
      return currentClass;
    } else {
      UmlClass _superType_1 = currentClass.getSuperType();
      return this.fetchRootClass(_superType_1);
    }
  }
}
